package com.dg.acb.utils.task;

import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.ThreadPoolExecutor.AbortPolicy;

import com.dg.acb.utils.LogUtil;

public class NBExecutor implements Executor {
    private ThreadPoolExecutor mPool;
    private int mCorePoolSize;
    private int mMaximumPoolSize;
    private long mKeepAliveTime;

    private NBExecutor(int corePoolSize, int maximumPoolSize,
            long keepAliveTime) {
        mCorePoolSize = corePoolSize;
        mMaximumPoolSize = maximumPoolSize;
        mKeepAliveTime = keepAliveTime;
    }

    /** 执行任务，当线程池处于关闭，将会重新创建新的线程池 */
    @Override
    public void execute(Runnable run) {
        if (run == null) {
            if (LogUtil.DEBUG) {
                LogUtil.e("execute Runnable is null");
            }
            return;
        }
        if (mPool == null || mPool.isShutdown()
                || mPool.isTerminated()
                || mPool.isTerminating()) {
            init();
        }
        mPool.execute(run);
    }

    private void init() {
        // 参数说明
        // 当线程池中的线程小于mCorePoolSize，直接创建新的线程加入线程池执行任务
        // 当线程池中的线程数目等于mCorePoolSize，将会把任务放入任务队列BlockingQueue中
        // 当BlockingQueue中的任务放满了，将会创建新的线程去执行，
        // 但是当总线程数大于mMaximumPoolSize时，将会抛出异常，交给RejectedExecutionHandler处理
        // mKeepAliveTime是线程执行完任务后，且队列中没有可以执行的任务，存活的时间，后面的参数是时间单位
        // ThreadFactory是每次创建新的线程工厂
        mPool = new ThreadPoolExecutor(mCorePoolSize, mMaximumPoolSize,
                mKeepAliveTime, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>(),
                Executors.defaultThreadFactory(), new AbortPolicy());
    }

    /** 取消线程池中某个还未执行的任务 */
    public synchronized void cancel(Runnable run) {
        if (mPool != null && (!mPool.isShutdown() || mPool.isTerminating())) {
            mPool.getQueue().remove(run);
        }
    }

    /** 取消线程池中某个还未执行的任务 */
    public synchronized boolean contains(Runnable run) {
        if (mPool != null && (!mPool.isShutdown() || mPool.isTerminating())) {
            return mPool.getQueue().contains(run);
        } else {
            return false;
        }
    }

    /** 平缓关闭单任务线程池，但是会确保所有已经加入的任务都将会被执行完毕才关闭 */
    public synchronized void shutdown() {
        if (mPool != null && (!mPool.isShutdown() || mPool.isTerminating())) {
            mPool.shutdownNow();
        }
    }

    public static NBExecutor getDownloadPool() {
        return InnerClass.sDownloadPool;
    }

    public static NBExecutor getLongPool() {
        return InnerClass.sLongPool;
    }

    public static NBExecutor getShortPool() {
        return InnerClass.sShortPool;
    }

    public static NBExecutor getImageDownloadPool() {
        return InnerClass.sImageDownloadPool;
    }

    public static NBExecutor getSinglePool() {
        return InnerClass.sSinglePool;
    }

    public static NBExecutor newSinglePool() {
        return new NBExecutor(1, 1, 5L);
    }

    private static class InnerClass {
        /** 下载线程 */
        static NBExecutor sDownloadPool = new NBExecutor(2, 3, 5L);
        /** 长耗时任务的线程池，避免和短耗时任务处在同一个队列而阻塞了重要的短耗时任务，通常用来联网操作 */
        static NBExecutor sLongPool = new NBExecutor(6, 7, 5L);
        /** 短耗时任务的线程池，避免因为和耗时长的任务处在同一个队列而长时间得不到执行，通常用来执行本地的IO/SQL */
        static NBExecutor sShortPool = new NBExecutor(3, 4, 5L);
        /** 图片下载的线程池 */
        static NBExecutor sImageDownloadPool = new NBExecutor(3, 4, 5L);
        /** 单线程池，所有任务将会被按照加入的顺序执行，免除了同步开销的问题 */
        static NBExecutor sSinglePool = new NBExecutor(1, 1, 5L);
    }
}
